package durak.server.servlets;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;

import durak.common.control.GameCommand;
import durak.common.control.GameCommand.CommandType;
import durak.common.model.Card;
import durak.common.model.Card.Rank;
import durak.common.model.Card.Suit;
import durak.common.model.Cards;
import durak.common.model.GameTableState;
import durak.logic.UserManager;
import durak.server.control.Game;
import durak.server.control.GamesManager;
import durak.server.control.PlayerControl;
import durak.server.control.PlayerControlHuman;
import durak.server.model.GamingTable;
import durak.server.model.Player.playerType;
import durak.utils.ServletUtils;
import durak.utils.SessionUtils;

/**
 * Servlet implementation class RunningGame
 */
@WebServlet(name = "runningGame", urlPatterns = { "/runningGame" })
public class RunningGame extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public RunningGame() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Servlet#getServletInfo()
	 */
	public String getServletInfo() {
		// TODO Auto-generated method stub
		return null; 
	}

	private void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String username = SessionUtils.getUsername(request);
		if (username == null) {
			response.sendRedirect("index.jsp");
		} else {
			Gson gson = new Gson();
			boolean ret = true;
			CommandType commandtype = gson.fromJson(request.getParameter("command"), GameCommand.CommandType.class);
			switch (commandtype) {
			case C2S_JOIN:
				handleJoinCommand(request, response, commandtype);	
				break;
			case C2S_GET_GAME_STATE:
				ret = handleGetGameStateCommand(request, response);
				break;
			case C2S_ATTACKED:
			case C2S_DEFENDED:
				ret = handleCardsActionCommand(request, response, commandtype);
				break;
			case C2S_WITHDRAWN:
			case C2S_PASS_ATTACK:
				ret = handleSimpleCommand(request, response, commandtype);
			default:
				break;
			}
			if(ret == false) {
				System.out.println("Redirecting to gamesRoom.jsp");
				response.sendRedirect("gamesRoom.jsp");
			}
		}
		response.getWriter().flush();
	}

	private boolean handleCardsActionCommand(HttpServletRequest request, HttpServletResponse response, CommandType commandtype) throws IOException {
		Gson gson = new Gson();
		GamesManager gameManager = ServletUtils.getGamesManager(getServletContext());
		String playerName = SessionUtils.getUsername(request);
		String gameName = ServletUtils.getUserManager(getServletContext()).getUserGameMapping(playerName);
		if(gameManager.isGameExists(gameName)) {
			PlayerControlHuman playerControl = gameManager.getGame(gameName).getPlayerByName(playerName);
			Cards cards = new Cards();
			Integer numOfCards = gson.fromJson(request.getParameter("numOfCards"), Integer.class);
			for (int i = 0; i < numOfCards; i++) {
				Rank rank = gson.fromJson(request.getParameter("cards[" + i + "][rank]"), Card.Rank.class);
				Suit suit = gson.fromJson(request.getParameter("cards[" + i + "][suit]"), Card.Suit.class);
				cards.addCard( new Card(rank, suit));
			}
			
			GameCommand gameCommand = new GameCommand(commandtype);
			gameCommand.setGameName(gameName);
			gameCommand.setPlayerName(playerName);
			gameCommand.setCards(cards);
			playerControl.handleGameCommand(gameCommand);
		} else {
			return false;
		}
		return true;
	}

	private boolean handleSimpleCommand(HttpServletRequest request, HttpServletResponse response, CommandType commandtype) throws IOException {
		GamesManager gameManager = ServletUtils.getGamesManager(getServletContext());
		String playerName = SessionUtils.getUsername(request);
		String gameName = ServletUtils.getUserManager(getServletContext()).getUserGameMapping(playerName);
		if(gameManager.isGameExists(gameName)) {
			PlayerControlHuman playerControl = gameManager.getGame(gameName).getPlayerByName(playerName);
			GameCommand gameCommand = new GameCommand(commandtype);
			gameCommand.setGameName(gameName);
			gameCommand.setPlayerName(playerName);
			playerControl.handleGameCommand(gameCommand);
		} else {
			return false;
		}
		return true;
	}

	private boolean handleGetGameStateCommand(HttpServletRequest request,	HttpServletResponse response) throws IOException {
		Gson gson = new Gson();
		GamesManager gameManager = ServletUtils.getGamesManager(getServletContext());
		String playerName = SessionUtils.getUsername(request);
		String gameName = ServletUtils.getUserManager(getServletContext()).getUserGameMapping(playerName);
		if(gameManager.isGameExists(gameName)) {
			PlayerControlHuman playerControl = gameManager.getGame(gameName).getPlayerByName(playerName);
			String jsonGameState = gson.toJson(playerControl.getCurrentGameCommand());
			System.out.println("Sending to " + playerName + " game state as json: " + jsonGameState);
			response.getWriter().print(jsonGameState);
		} else {
			return false;
		}
		return true;
	}

	private void handleJoinCommand(HttpServletRequest request, HttpServletResponse response, CommandType commandtype) throws ServletException, IOException {
		Gson gson = new Gson();
		String gameName = request.getParameter("game-name");
		String playerName = SessionUtils.getUsername(request);
		GamesManager gameManager = ServletUtils.getGamesManager(getServletContext());
		if(gameManager.isGameExists(gameName)) {
			UserManager userManger = ServletUtils.getUserManager(getServletContext());
			userManger.addUserGameMapping(playerName, gameName);
			Game theGame = gameManager.getGame(gameName);
			PlayerControl player = new PlayerControlHuman(theGame);
			player.getPlayer().setType(playerType.HUMAN);
			player.getPlayer().setName(playerName);
			player.setInitialized(true);
			theGame.addPlayer(player);
			if (theGame.isGameFull()) {
				theGame.getGamingTable().setGameStarted(true);
				System.out.println("All players are connected. Starting game...");
				theGame.getCommandHandler().runGame();
			}
		}
		System.out.println("Redirecting " + playerName + " to /WebDurak/GameTable.jsp");
		response.getWriter().print(gson.toJson(response.encodeRedirectURL("/WebDurak/GameTable.jsp")));
	}
	
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		handleRequest(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		handleRequest(request, response);
	}
}
